﻿//===============================================================================
// Apolineo Patterns & Practices LeanEngine Framework
//===============================================================================
// Copyright © Apolineo Desenvolvimento de Sistemas Ltda.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================

using System;
using System.Data;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using LeanEngine.Data;
using LeanEngine.Entity;
using LeanEngine.Extensions;

using LeanEngine.SalesConcept.Entity;

namespace LeanEngine.SalesConcept.Repository
{
    //Classe de acesso a dados
    internal static class SaleRepository
    {
        //Método para exclusão dos itens da venda
        //Foi criado como método de extensão para dar uma melhor semântica ao código
        internal static int DeleteSaleDetails(this Sale sale)
        {
            using (DataCommand cmd = new DataCommand())
            {
                var saleTable = MetaTableCache.GetItem(typeof(Sale));
                var saleDetailTable = MetaTableCache.GetItem(typeof(SaleDetail));
                var saleColumn = saleDetailTable.ColumnsList.Where(c => c.PropertyName == "Sale").First();

                //Aqui utilizamos o reflaction para criar um comando para deletar os
                //detalhes da venda e mantendo o comando multi-banco

                //Utilizamos o método de extensão GetTableName (Data) para obter 
                //o nome da Tabela e o GetColumnName (Data) para obter o nome da
                //coluna. Nesse cenário é recomendável utilizar esses métodos de
                //extensão para que o lob faça cache dos metadados e o sistema não
                //tenha uma gradação de performance menor (isso quando sobre forte
                //concorrencia)
                cmd.CommandText = "DELETE FROM [" +
                                    saleTable.TableName + 
                                    "] WHERE [" +
                                    saleColumn.DBColumn.Name + 
                                    "] = @Param";

                cmd.Parameters.Add(cmd.NewParameter("Param", sale.Id));

                return cmd.ExecuteNonQuery();
            }
        }

        //Método de pesquisa de vendas criado para ilustrar a utilização de stored procedures
        //Não foi criado como método de extensão porque não traz semântica ao código
        public static List<Sale> ListSales(SaleSearchCriteria searchCriteria)
        {
            using (DataCommand cmd = new DataCommand())
            {
                cmd.CommandText = "proc_GetSales";
                cmd.CommandType = CommandType.StoredProcedure;

                cmd.Parameters.Add(cmd.NewParameter("PageIndex", searchCriteria.PageIndex));
                cmd.Parameters.Add(cmd.NewParameter("PageSize", searchCriteria.PageSize));
                cmd.Parameters.Add(cmd.NewParameter("CustomerId", searchCriteria.CustomerId.IsLessThanEqual(0) ? DBNull.Value : (object)searchCriteria.CustomerId));
                cmd.Parameters.Add(cmd.NewParameter("SalesmanId", searchCriteria.SalesmanId.IsLessThanEqual(0) ? DBNull.Value : (object)searchCriteria.SalesmanId));
                cmd.Parameters.Add(cmd.NewParameter("ProductId", searchCriteria.ProductId.IsLessThanEqual(0) ? DBNull.Value : (object)searchCriteria.ProductId));
                cmd.Parameters.Add(cmd.NewParameter("BeginSaleDate", searchCriteria.BeginDate.HasDefaultDate() ? DBNull.Value : (object)searchCriteria.BeginDate));
                cmd.Parameters.Add(cmd.NewParameter("EndSaleDate", searchCriteria.EndDate.HasDefaultDate() ? DBNull.Value : (object)searchCriteria.EndDate));

                //O lob possui mapeamento padrão de resultado da pesquisa para a classe quando o schema
                //da pesquisa são iguais aos das colunas declaradas através do atributo Column, porém,
                //para casos como esse em que a consulta retorna um schema diferente podemos criar um
                //método anonimo para fazermos nosso próprio mapeamento

                //No exemplo abaixo usamos um método de extensão para o mapeamento padrão e codificamos
                //o mapeamento customizado

                //O método ExecuteReader<T> é específico do lob e mapeia o resultado da consulta em uma
                //coleção do tipo List<T> de acordo com o tipo específicado
                return cmd.ExecuteReader<Sale>((item, resultSet) =>
                {
                    //Método de extensão padrão para mapear os resultados da consulta nas classes
                    item.Fill(resultSet);

                    item.Customer.Name = resultSet["CustomerName"].ToString();
                    item.Salesman.Name = resultSet["SalesmanName"].ToString();
                });
            }
        }

        //Método de contagem de registros a serem retornados pela pesquisa de vendas 
        //criado para ilustrar a utilização de stored procedures

        //Não foi criado como método de extensão porque não traz semântica ao código
        internal static long CountSales(SaleSearchCriteria searchCriteria)
        {
            using (DataCommand cmd = new DataCommand())
            {
                cmd.CommandText = "proc_GetCountSales";
                cmd.CommandType = CommandType.StoredProcedure;

                cmd.Parameters.Add(cmd.NewParameter("CustomerId", searchCriteria.CustomerId.IsLessThanEqual(0) ? DBNull.Value : (object)searchCriteria.CustomerId));
                cmd.Parameters.Add(cmd.NewParameter("SalesmanId", searchCriteria.SalesmanId.IsLessThanEqual(0) ? DBNull.Value : (object)searchCriteria.SalesmanId));
                cmd.Parameters.Add(cmd.NewParameter("ProductId", searchCriteria.ProductId.IsLessThanEqual(0) ? DBNull.Value : (object)searchCriteria.ProductId));
                cmd.Parameters.Add(cmd.NewParameter("BeginSaleDate", searchCriteria.BeginDate.HasDefaultDate() ? DBNull.Value : (object)searchCriteria.BeginDate));
                cmd.Parameters.Add(cmd.NewParameter("EndSaleDate", searchCriteria.EndDate.HasDefaultDate() ? DBNull.Value : (object)searchCriteria.EndDate));

                return cmd.ExecuteScalar().ToInt64();
            }
        }
    }
}
